package com.gitee.jmash.rbac.utils;

import java.util.List;
import java.util.stream.Collectors;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.eclipse.microprofile.jwt.JsonWebToken;
import com.gitee.jmash.common.event.SafeEvent;
import com.gitee.jmash.common.grpc.GrpcContext;
import com.gitee.jmash.common.security.JmashPrincipal;
import com.gitee.jmash.common.utils.UUIDUtil;
import com.gitee.jmash.rbac.entity.RoleEntity;
import com.gitee.jmash.rbac.entity.UserEntity;
import jakarta.enterprise.event.Event;
import jmash.rbac.protobuf.RunAsReq;
import jmash.rbac.protobuf.UserModel;

/**
 * 已某身份运行封装.
 *
 * @author cgd
 */
public class RunAsUtil {

  /** 某种身份运行. */
  public static void runAs(RunAsReq request, UserEntity toUser, Event<SafeEvent> event)
      throws Exception {
    Subject subject = (Subject) GrpcContext.USER_SUBJECT.get();
    // 是否收回身份
    if (subject.isRunAs()) {
      subject.releaseRunAs();
    }
    // 检查权限
    if (!subject.hasRole(RoleEntity.TESTER)) {
      throw new RuntimeException("该用户没有切换身份权限！");
    }
    JmashPrincipal oldp = GrpcContext.getPrincipal();
    // 切换到其他身份
    if (!toUser.getUserId().equals(oldp.getNameUUID())) {
      // Shiro登录凭证
      JsonWebToken webToken = TokenUtil.createJsonWebToken(request.getTenant(), toUser,
          toUser.getStorage(), oldp.getClientId(), toUser.getLoginName(), request.getScope());
      // 新身份运行
      subject.runAs(new SimplePrincipalCollection(webToken, toUser.getDirectoryId()));
      String content = String.format("原用户: %s,切换到用户 : %s ", oldp.getSubject(), webToken.getSubject());
      event.fireAsync(SafeEvent.runAs(content, request.getTenant()));
    }
  }

  /** 标记用户runAs信息. */
  public static List<UserModel> markRunAsInfo(List<UserModel> resp) {
    Subject subject = (Subject) GrpcContext.USER_SUBJECT.get();
    // 切换身份运行
    if (subject.isRunAs()) {
      resp = resp.stream().map(user -> markRunAsInfo(user)).collect(Collectors.toList());
    }
    return resp;
  }

  /** 标记用户runAs信息. */
  public static UserModel markRunAsInfo(UserModel resp) {
    Subject subject = (Subject) GrpcContext.USER_SUBJECT.get();
    JsonWebToken cur = (JsonWebToken) subject.getPrincipal();
    if (subject.isRunAs() && UUIDUtil.equals(resp.getUserId(), cur.getName())) {
      JsonWebToken previousPrimary =
          (JsonWebToken) subject.getPreviousPrincipals().getPrimaryPrincipal();
      resp = resp.toBuilder().setRunAs(true).setPrimaryUserId(previousPrimary.getName()).build();
    }
    return resp;
  }

}
